/*********************************************************
/* video.c						 *
/* Functions for screen output (text)			 *
/*********************************************************/

#define WHITE 0x07	/* Color white for vmem text output */
#define VIDEO 0xb8000   /* Video memory address */
#define COLUMNS 80	/* 80 Columns on the screen */
#define LINES 24	/* 24 Lines on the screen */

#include <kernel.h>

unsigned int xpos;	/* Text output x position (Column) */
unsigned int ypos;	/* Text output y position (Row) */
unsigned char *vidmem;	/* Pointer to the video memory address */

void k_print_welcomemsg(unsigned int spacebefore, unsigned int spaceafter) {
	
	int i=0;
	int x=0;

	while (i<spacebefore) {
		printf("\n");
		i++;
	}

	printf("##      ## ######## ##        ######   #######  ##     ## ######## ####\n");
	printf("##  ##  ## ##       ##       ##    ## ##     ## ###   ### ##       ####\n");
	printf("##  ##  ## ##       ##       ##       ##     ## #### #### ##       ####\n");
	printf("##  ##  ## ######   ##       ##       ##     ## ## ### ## ######    ## \n");
	printf("##  ##  ## ##       ##       ##       ##     ## ##     ## ##           \n");
	printf("##  ##  ## ##       ##       ##    ## ##     ## ##     ## ##       ####\n");
	printf(" ###  ###  ######## ########  ######   #######  ##     ## ######## ####\n");
	printf("------------------------- %s %s -------------------------- \n", (unsigned char *)OS_NAME, (unsigned char *)OS_VER);

	while (x<spaceafter) {
		printf("\n");
		x++;
	}

}

void k_printmemmap(unsigned int highmem, unsigned int lowmem, unsigned int spacebefore, unsigned int spaceafter) {

	int i=0;
	int x=0;

	while (i<spacebefore) {
		printf("\n");
		i++;
	}
	
	printf("Probing memory ...\n\n");

	printf("Low memory: %uKB\n", (unsigned) highmem);
	printf("High memory: %uKB", (unsigned) lowmem);

	while (x<spaceafter) {
		printf("\n");
		x++;
	}

}

/* Initialize the vidmem pointer to the correct address for printing to the screen */
void k_initvideo() {

	vidmem = (unsigned char *) VIDEO;
	xpos = 0;
	ypos = 0;

}

/* clear the entire text screen and initialized video */
void k_clear_screen()
{
	unsigned int i=0;
	while(i < (80*25*2)) 
	{
		vidmem[i++]=' ';
		vidmem[i++]=WHITE;
	};
};

static void itoa (char *buf, int base, int d)
{
  char *p = buf;
  char *p1, *p2;
  unsigned long ud = d;
  int divisor = 10;
  
  /* If %d is specified and D is minus, put `-' in the head. */
  if (base == 'd' && d < 0)
    {
      *p++ = '-';
      buf++;
      ud = -d;
    }
  else if (base == 'x')
    divisor = 16;

  /* Divide UD by DIVISOR until UD == 0. */
  do
    {
      int remainder = ud % divisor;
      
      *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
    }
  while (ud /= divisor);

  /* Terminate BUF. */
  *p = 0;
  
  /* Reverse BUF. */
  p1 = buf;
  p2 = p - 1;
  while (p1 < p2)
    {
      char tmp = *p1;
      *p1 = *p2;
      *p2 = tmp;
      p1++;
      p2--;
    }
}

/* Put the character C on the screen. */
static void putchar (int c)
{
  if (c == '\n' || c == '\r')
    {
    newline:
      xpos = 0;
      ypos++;
      if (ypos >LINES) {
      	k_pushup_screen();
	ypos--;
      }
      return;
    }

  *(vidmem + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
  *(vidmem + (xpos + ypos * COLUMNS) * 2 + 1) = WHITE;

  xpos++;
  if (xpos >= COLUMNS)
    goto newline;
}

/* Format a string and print it on the screen, just like the libc
   function printf. */
void printf (const char *format, ...)
{
  char **arg = (char **) &format;
  int c;
  char buf[20];

  arg++;
  
  /*Push text over by 1 character. */
  putchar(' ');

  while ((c = *format++) != 0)
    {
      if (c != '%')
        putchar (c);
      else
        {
          char *p;
          
          c = *format++;
          switch (c)
            {
            case 'd':
            case 'u':
            case 'x':
              itoa (buf, c, *((int *) arg++));
              p = buf;
              goto string;
              break;

            case 's':
              p = *arg++;
              if (! p)
                p = "(null)";

            string:
              while (*p)
                putchar (*p++);
              break;

            default:
              putchar (*((int *) arg++));
              break;
            }
        }
    }
}

/* Pushes the screen up by 1 line.
   Usually this is called once the text output has exceeded 25 lines. */
void k_pushup_screen() {

	memcpy(vidmem, vidmem + (80 * 2), 80*25*2);

}
